package nsqlookupd

import (
	"io"
	"net"

	"github.com/nsqio/nsq/internal/protocol"
)

type tcpServer struct {
	ctx *Context
}
// nsqlookupd接收到tcp数据时，会调用本方法处理。
//实现了internal/tcp_server.go中定义的TCPHandler接口
func (p *tcpServer) Handle(clientConn net.Conn) {
	p.ctx.nsqlookupd.logf(LOG_INFO, "TCP: new client(%s)", clientConn.RemoteAddr())

	//客户端在初始化自己的时候，需要发送4字节的数据用来标识它自己所有使用协议版本。将来升级协议的时候可以避免使用旧协议的客户端不能使用。
	buf := make([]byte, 4)
	_, err := io.ReadFull(clientConn, buf)
	if err != nil {
		p.ctx.nsqlookupd.logf(LOG_ERROR, "failed to read protocol version - %s", err)
		clientConn.Close()
		return
	}
	//获取协议内容
	protocolMagic := string(buf)

	p.ctx.nsqlookupd.logf(LOG_INFO, "CLIENT(%s): desired protocol magic '%s'",
		clientConn.RemoteAddr(), protocolMagic)

	//internal/Protocol.go中定义了一个Protocol的接口
	var prot protocol.Protocol

	switch protocolMagic {
	case "  V1":
		//当前只支持"  V1"协议（前两有两个空格，所以总共是4字节），协议在nsqlookupd\lookup_protocol_v1.go文件中定义，这里创建了LookupProtocolV1的实例
		//LookupProtocolV1实现了Protocol接口
		prot = &LookupProtocolV1{ctx: p.ctx}
	default:
		// 不是 V1 版本返回错误
		protocol.SendResponse(clientConn, []byte("E_BAD_PROTOCOL"))
		clientConn.Close()
		p.ctx.nsqlookupd.logf(LOG_ERROR, "client(%s) bad protocol magic '%s'",
			clientConn.RemoteAddr(), protocolMagic)
		return
	}
	//如果是"  V1"f协议，这里就进入了LookupProtocolV1的IOLoop方法。此方法里有for死循环运行，直到出现error时，才会执行下面的代码。
	err = prot.IOLoop(clientConn)

	if err != nil {
		p.ctx.nsqlookupd.logf(LOG_ERROR, "client(%s) - %s", clientConn.RemoteAddr(), err)
		return
	}
}
